<?php

namespace App\Services;

use RuntimeException;
use Illuminate\Encryption\Encrypter;
use Illuminate\Support\Str;

class JsCryptService
{
    //请求秘钥
    static $requestKey = null;

    //返回秘钥
    static $returnKey = null;

    /**
     *
     * @param mixed $key
     *
     * @return boolean
     */
    public static function checkKey($key)
    {
        if (!preg_match("/^[0-9a-zA-Z]{1,}$/", $key)) {
            return false;
        }
        return true;
    }


    /**
     * 请求加密
     * @param mixed $data
     * @param mixed $key 必须用a-zA-Z0-9 。  目前是时间戳
     *
     * @return array|null
     */
    public static function requestEncrypt($data, $key = null)
    {
        if (is_null(self::$requestKey)) {
            self::$requestKey = $key;
        }

        if (!self::checkKey($key)) {
            return null;
        }

        $base_e_str = self::_base64UrlEncode($data);
        $t = $base_e_str . self::$requestKey;
        $len = strlen($t);
        $per = intval($len / 6);
        //var_dump($per);
        if ($per < 2) {
            return ['self::_base64UrlEncode' => $base_e_str, 'e' => urlencode($t)];
        }
        $per_0 = $per - 1;

        $i = 0;
        $t_len = $len;
        $arr_per_0 = [];
        $arr_per = [];
        $arr_last = [];
        $t_start = 0;
        while (true) {
            if ($i % 2 === 0) {
                if ($t_len / $per_0 > 1) {
                    $arr_per_0[] = substr($t, $t_start, $per_0);
                } else {
                    //echo "{$t}[{$t_start}]\n";
                    //var_dump(substr($t, $t_start));
                    $arr_last[] = substr($t, $t_start); //第三个参数直到末端，不填
                    break;
                }
                $t_start += $per_0;
                $t_len = $t_len - $per_0;
            } else {

                if ($t_len / $per > 1) {
                    $arr_per[] = substr($t, $t_start, $per);
                } else {
                    //echo "{$t}[{$t_start}]\n";
                    //var_dump(substr($t, $t_start));
                    $arr_last[] = substr($t, $t_start);
                    break;
                }
                $t_start += $per;
                $t_len = $t_len - $per;
            }
            $i++;
        }

        $sdata = implode("", $arr_last) . implode("", $arr_per) . implode("", $arr_per_0);
        $arr = ['base64_encode' => $base_e_str, 'e' => $sdata];
        return $arr;
    }


    /**
     * 请求解密
     * @param mixed $data
     *
     * @return array|null
     */
    public static function requestDecrypt($data, $key = null)
    {
        if (is_null(self::$requestKey)) {
            self::$requestKey = $key;
        }

        if (!self::checkKey($key)) {
            return null;
        }

        $t = $data;
        $len = strlen($t);
        $per = intval($len / 6);
        if ($per < 2) {
            $len_key = strlen(self::$requestKey);
            $base64_estr = substr($t, 0, $len - $len_key);
            return ['base64_encode' => $base64_estr, 'd' => self::_base64UrlDecode($base64_estr)];
        }
        $per_0 = $per - 1;

        $i = 0;
        $t_len = $len;
        $arr_per_0_num = [];
        $arr_per_num = [];
        while (true) {
            if ($i % 2 === 0) {
                if ($t_len / $per_0 > 1) {
                    $arr_per_0_num[] = $per_0;
                } else {
                    break;
                }
                $t_len = $t_len - $per_0;
            } else {

                if ($t_len / $per > 1) {
                    $arr_per_num[] = $per;
                } else {
                    break;
                }
                $t_len = $t_len - $per;
            }
            $i++;
        }

        $arr_per_0 = [];
        $arr_per = [];
        $t_start = 0;
        $t_count = count($arr_per_0_num);
        foreach ($arr_per_0_num as $k => $per_0) {
            $t_start -= $per_0;
            $arr_per_0[$t_count - 1 - $k] = substr($t, $t_start, $per_0);
        }

        $t_count = count($arr_per_num);
        foreach ($arr_per_num as $k => $per) {
            $t_start -= $per;
            $arr_per[$t_count - 1 - $k] = substr($t, $t_start, $per);
        }


        $last_str = substr($t, 0, $len + $t_start);

        $i = 0;
        $max = max(count($arr_per_0), count($arr_per));
        $str = "";
        for ($i = 0; $i < $max; $i++) {
            if (isset($arr_per_0[$i])) {
                $str .= $arr_per_0[$i];
            }

            if (isset($arr_per[$i])) {
                $str .= $arr_per[$i];
            }
        }

        $str .= $last_str;
        $len_key = strlen(self::$requestKey);
        $str = substr($str, 0, $len - $len_key);

        return ['base64_encode' => $str, 'd' => self::_base64UrlDecode($str)];
    }


    public static function returnEncrypt($data, $key = null)
    {
        if (self::$returnKey === null) {
            self::$returnKey = $key;
        }

        if (!self::checkKey($key)) {
            return null;
        }

        $base_e_str = self::base64UrlEncode($data);
        $t = $base_e_str . self::$returnKey;
        $len = strlen($t);
        $per = intval($len / 4);
        if ($per < 2) {
            return ['base64_encode' => $base_e_str, 'e' => urlencode($t)];
        }

        $i = 0;
        $t_len = $len;
        $arr_per = [];
        $arr_last = [];
        $t_start = 0;
        while (true) {
            if ($t_len / $per > 1) {
                $arr_per[] = substr($t, $t_start, $per);
            } else {
                $arr_last[] = substr($t, $t_start);
                break;
            }
            $t_start += $per;
            $t_len = $t_len - $per;
            $i++;
        }

        $sdata = implode("", $arr_last) . implode("", $arr_per);
        $arr = ['base64_encode' => $base_e_str, 'e' => $sdata];
        return $arr;
    }


    public static function returnDecrypt($data, $key = null)
    {
        if (self::$returnKey === null) {
            self::$returnKey = $key;
        }

        if (!self::checkKey($key)) {
            return null;
        }

        $t = $data;
        $len = strlen($t);
        $per = intval($len / 4);
        if ($per < 2) {
            $len_key = strlen(self::$returnKey);
            $base64_estr = substr($t, 0, $len - $len_key);
            return ['base64_encode' => $base64_estr, 'd' => self::base64UrlDecode($base64_estr)];
        }
        $i = 0;
        $t_len = $len;
        $arr_per_num = [];
        while (true) {
            if ($t_len / $per > 1) {
                $arr_per_num[] = $per;
            } else {
                break;
            }
            $t_len = $t_len - $per;
            $i++;
        }

        $arr_per = [];
        $t_start = 0;
        $t_count = count($arr_per_num);
        foreach ($arr_per_num as $k => $per) {
            $t_start -= $per;
            $arr_per[$t_count - 1 - $k] = substr($t, $t_start, $per);
        }

        $last_str = substr($t, 0, $len + $t_start);

        $i = 0;
        $max = count($arr_per);
        $str = "";
        for ($i = 0; $i < $max; $i++) {
            if (isset($arr_per[$i])) {
                $str .= $arr_per[$i];
            }
        }

        $str .= $last_str;
        $len_key = strlen(self::$returnKey);
        $str = substr($str, 0, $len - $len_key);
        return ['base64_encode' => $str, 'd' => self::base64UrlDecode($str)];
    }

    /**
     * get传输的编码功能   因为客户端提交时，服务器自动url解码一次。base64的字符会被转换
     * @param mixed $data
     *
     * @return string
     */
    private static function base64UrlEncode($data)
    {
        $data = base64_encode($data);
        $data = strtr($data, '+/', '-_');
        // 默认情况下，取消对编码的填充，因为它不需要解码，并且保持URL不含%编码。
        $data = rtrim($data, '=');
        return $data;
    }

    /**
     * get传输的解码功能
     * @param mixed $data
     *
     * @return string
     */
    private static function base64UrlDecode($data)
    {
        $data = strtr($data, '-_', '+/');
        return base64_decode($data);
    }

}
